package codetype.filter;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import codetype.annotation.CodeType;
import codetype.annotation.TranslateCode;
import codetype.cache.CodeTypeCache;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 拦截
 *
 * @author zhanghui145
 * @date 2021/12/28 19:18
 * @since 1.0.0
 */
@ControllerAdvice
public class ResponseModifyFilter implements ResponseBodyAdvice<Object> {

    /**
     * 判断是否要执行beforeBodyWrite方法，true为执行，false不执行
     *
     * @param returnType    方法参数
     * @param converterType type
     * @return 是否执行beforeBodyWrite方法
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        Annotation[] ats = returnType.getMethodAnnotations();
        for (Annotation at : ats) {
            if (Objects.equals(at.annotationType(), TranslateCode.class)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType, Class selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        return transSingle(body);
    }

    /**
     * 对单个对象翻译
     *
     * @param object 对象object
     * @return 翻译后的json
     */
    private JSON transSingle(Object object) {
        if (object instanceof Map || object instanceof String) {
            return JSONUtil.parse(object);
        }
        if (object instanceof List) {
            return this.transArray(object);
        }
        Map<Field, Object> fieldStringMap = codeTypeFields(object);
        return transCode(JSONUtil.parseObj(object), fieldStringMap);
    }

    /**
     * 嵌套对象翻译
     *
     * @param object array对象
     * @return 翻译后的嵌套对象
     */
    private JSON transArray(Object object) {
        List<?> objects = (List<?>) object;
        JSONArray array = new JSONArray();
        for (Object o : objects) {
            array.add(this.transSingle(o));
        }
        return array;
    }

    /**
     * 已经拿到了需要翻译的字段(map)，进行翻译，然后把翻译值放到对象json里
     * 对嵌套对象特殊处理
     *
     * @param json      对象json
     * @param fieldCode 对象里加需要翻译的字段map
     * @return 翻译后的json
     */
    private JSON transCode(JSONObject json, Map<Field, Object> fieldCode) {
        Map<String, String> map = new HashMap<>();
        for (Map.Entry<Field, Object> entry : fieldCode.entrySet()) {
            String fieldName = entry.getKey().getName();
            Object val = entry.getValue();
            Object object = json.get(fieldName);

            String transVal = CodeTypeCache.getValByKey((String)val, (String) object);
            map.put(fieldName + "TranslateText", transVal);
        }
        json.putAll(map);
        return json;
    }

    /**
     * 得到Object里加了@CodeType的字段
     *
     * @param body 返回值Object
     * @return Map, Field:字段，String:codeType值
     */
    private Map<Field, Object> codeTypeFields(Object body) {
        Map<Field, Object> codes = new HashMap<>();
        Class<?> clz = body.getClass();
        for (Field field : clz.getDeclaredFields()) {
            if ("interface java.util.List".equals(field.getType().toString())) {
                // 在这里处理，但是实际没必要
            }
            CodeType codeType = field.getAnnotation(CodeType.class);
            if (Objects.nonNull(codeType)) {
                codes.put(field, codeType.type());
            }
        }
        return codes;
    }
}